package Games.Gobang.Game;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class Regulation {
	private static final String TAG = "Games.Gobang.Game.Regulation";
	private final static ChessmanTypes[][] chessBoard = new ChessmanTypes[40][40];
	private int maxX;
	private int maxY;
	private Handler mHandler;
	private int win_series = 5;
	private java.util.Stack<BoardPoint> chessmanStack = new java.util.Stack<BoardPoint>();

	public enum GameStates {
		NotStart, Started, Over, NoSpace
	}

	private GameStates gameState;

	public Regulation(int x, int y, Handler handler) {
		maxX = x;
		maxY = y;
		mHandler = handler;
		ResetGame();
	}

	public void SetBoardRange(int x, int y) {
		maxX = x;
		maxY = y;
		ResetGame();
	}

	@SuppressWarnings("unused")
	public void ResetGame() {
		gameState = GameStates.NotStart;
		for (ChessmanTypes[] cts : chessBoard) {
			for (ChessmanTypes ct : cts) {
				ct = ChessmanTypes.Black;
			}
		}
	}

	public void setWin_series(int win_series) {
		this.win_series = win_series;
	}

	public GameStates getGameState() {
		return gameState;
	}

	public void Start() {
		gameState = GameStates.Started;
	}

	public Boolean PutOnAChessman(int x, int y, ChessmanTypes ctype) {
		Boolean isSucess = false;
		int xInArray = x;
		int yInArray = y;

		if (gameState != GameStates.Started && IsInRange(xInArray, yInArray)
				&& IsCellEmpty(xInArray, yInArray)) {
			chessBoard[xInArray][yInArray] = ctype;
			CheckIfGameOver(xInArray, yInArray, ctype);
			BoardPoint bp = new BoardPoint(xInArray, yInArray, ctype);
			chessmanStack.push(bp);
			isSucess = true;
		} else {
			isSucess = false;
			Bundle bundle = new Bundle();
			bundle.putString(TAG,
					"game don't start; x or y axis is not in range; there is already a chessman.");
			Message msg = mHandler.obtainMessage(GameMessageTypes.Wrong_PutOn);
			msg.setData(bundle);
			mHandler.sendMessage(msg);
		}
		return isSucess;
	}

	public void TakeBack(ChessmanTypes ctype) {
		BoardPoint bp = chessmanStack.pop();
		chessBoard[bp.getX()][bp.getY()] = ChessmanTypes.Empty;
		if (bp.getChessmanType() != ctype) {
			bp = chessmanStack.pop();
			chessBoard[bp.getX()][bp.getY()] = ChessmanTypes.Empty;
		}
		gameState = GameStates.Started;
	}

	private void CheckIfGameOver(int xInArray, int yInArray, ChessmanTypes ctype) {
		// check left axis
		int x_check = xInArray - 1;
		int y_check = yInArray - 1;
		int series_number = 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check--;
			y_check--;
		}
		x_check = xInArray + 1;
		y_check = yInArray + 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check++;
			y_check++;
		}
		if (series_number >= win_series) {
			gameState = GameStates.Over;
			RaiseWinMsg(ctype);
		}

		// check right axis
		x_check = xInArray + 1;
		y_check = yInArray - 1;
		series_number = 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check++;
			y_check--;
		}
		x_check = xInArray - 1;
		y_check = yInArray + 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check--;
			y_check++;
		}
		if (series_number >= win_series) {
			gameState = GameStates.Over;
			RaiseWinMsg(ctype);
		}

		// check horizontal axis
		x_check = xInArray - 1;
		y_check = yInArray;
		series_number = 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check--;
		}
		x_check = xInArray + 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			x_check++;
		}
		if (series_number >= win_series) {
			gameState = GameStates.Over;
			RaiseWinMsg(ctype);
		}

		// check vertical axis
		x_check = xInArray;
		y_check = yInArray - 1;
		series_number = 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			y_check--;
		}
		y_check = yInArray + 1;
		while (IsInRange(xInArray, yInArray)
				&& chessBoard[x_check][y_check] == ctype) {
			series_number++;
			y_check++;
		}
		if (series_number >= win_series) {
			gameState = GameStates.Over;
			RaiseWinMsg(ctype);
		}
	}

	private void RaiseWinMsg(ChessmanTypes ctype) {
		Bundle bundle = new Bundle();
		int whoWin = ctype == ChessmanTypes.Black ? GameMessageTypes.Black_Win
				: GameMessageTypes.White_Win;
		bundle.putString(TAG, ctype.toString() + "Win");
		Message msg = mHandler.obtainMessage(whoWin);
		msg.setData(bundle);
		mHandler.sendMessage(msg);
	}

	private boolean IsInRange(int xInArray, int yInArray) {
		return (xInArray >= 0 && xInArray < maxX)
				&& (yInArray >= 0 && yInArray < maxY);
	}

	private boolean IsCellEmpty(int xInArray, int yInArray) {
		return chessBoard[xInArray][yInArray] == ChessmanTypes.Empty;

	}

}
